home *** CD-ROM | disk | FTP | other *** search
/ Aminet 44 / Aminet 44 (2001)(GTI - Schatztruhe)[!][Aug 2001].iso / Aminet / dev / misc / AmigaSDLsrc.lha / amisrc / SDL_RLEaccel.c < prev    next >
C/C++ Source or Header  |  2001-04-29  |  43KB  |  1,548 lines

  1. /*
  2.     SDL - Simple DirectMedia Layer
  3.     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
  4.  
  5.     This library is free software; you can redistribute it and/or
  6.     modify it under the terms of the GNU Library General Public
  7.     License as published by the Free Software Foundation; either
  8.     version 2 of the License, or (at your option) any later version.
  9.  
  10.     This library is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.     Library General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU Library General Public
  16.     License along with this library; if not, write to the Free
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19.     Sam Lantinga
  20.     slouken@devolution.com
  21. */
  22.  
  23. #ifdef SAVE_RCSID
  24. static char rcsid =
  25.  "@(#) $Id: SDL_RLEaccel.c,v 1.3.2.22 2001/02/17 17:52:09 hercules Exp $";
  26. #endif
  27.  
  28. /*
  29.  * RLE encoding for software colorkey and alpha-channel acceleration
  30.  *
  31.  * Original version by Sam Lantinga
  32.  *
  33.  * Mattias Engdegård (Yorick): Rewrite. New encoding format, encoder and
  34.  * decoder. Added per-surface alpha blitter. Added per-pixel alpha
  35.  * format, encoder and blitter.
  36.  *
  37.  * Many thanks to Xark and johns for hints, benchmarks and useful comments
  38.  * leading to this code.
  39.  *
  40.  * Welcome to Macro Mayhem.
  41.  */
  42.  
  43. /*
  44.  * The encoding translates the image data to a stream of segments of the form
  45.  *
  46.  * <skip> <run> <data>
  47.  *
  48.  * where <skip> is the number of transparent pixels to skip,
  49.  *       <run>  is the number of opaque pixels to blit,
  50.  * and   <data> are the pixels themselves.
  51.  *
  52.  * This basic structure is used both for colorkeyed surfaces, used for simple
  53.  * binary transparency and for per-surface alpha blending, and for surfaces
  54.  * with per-pixel alpha. The details differ, however:
  55.  *
  56.  * Encoding of colorkeyed surfaces:
  57.  *
  58.  *   Encoded pixels always have the same format as the target surface.
  59.  *   <skip> and <run> are unsigned 8 bit integers, except for 32 bit depth
  60.  *   where they are 16 bit. This makes the pixel data aligned at all times.
  61.  *   Segments never wrap around from one scan line to the next.
  62.  *
  63.  *   The end of the sequence is marked by a zero <skip>,<run> pair at the *
  64.  *   beginning of a line.
  65.  *
  66.  * Encoding of surfaces with per-pixel alpha:
  67.  *
  68.  *   The sequence begins with a struct RLEDestFormat describing the target
  69.  *   pixel format, to provide reliable un-encoding.
  70.  *
  71.  *   Each scan line is encoded twice: First all completely opaque pixels,
  72.  *   encoded in the target format as described above, and then all
  73.  *   partially transparent (translucent) pixels (where 1 <= alpha <= 254),
  74.  *   in the following 32-bit format:
  75.  *
  76.  *   For 32-bit targets, each pixel has the target RGB format but with
  77.  *   the alpha value occupying the highest 8 bits. The <skip> and <run>
  78.  *   counts are 16 bit.
  79.  * 
  80.  *   For 16-bit targets, each pixel has the target RGB format, but with
  81.  *   the middle component (usually green) shifted 16 steps to the left,
  82.  *   and the hole filled with the 5 most significant bits of the alpha value.
  83.  *   i.e. if the target has the format         rrrrrggggggbbbbb,
  84.  *   the encoded pixel will be 00000gggggg00000rrrrr0aaaaabbbbb.
  85.  *   The <skip> and <run> counts are 8 bit for the opaque lines, 16 bit
  86.  *   for the translucent lines. Two padding bytes may be inserted
  87.  *   before each translucent line to keep them 32-bit aligned.
  88.  *
  89.  *   The end of the sequence is marked by a zero <skip>,<run> pair at the
  90.  *   beginning of an opaque line.
  91.  */
  92.  
  93. #include <stdio.h>
  94. #include <stdlib.h>
  95. #include <string.h>
  96.  
  97. #include "SDL_types.h"
  98. #include "SDL_video.h"
  99. #include "SDL_error.h"
  100. #include "SDL_sysvideo.h"
  101. #include "SDL_blit.h"
  102. #include "SDL_memops.h"
  103. #include "SDL_RLEaccel_c.h"
  104.  
  105. #ifndef MAX
  106. #define MAX(a, b) ((a) > (b) ? (a) : (b))
  107. #endif
  108. #ifndef MIN
  109. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  110. #endif
  111.  
  112. /*
  113.  * Various colorkey blit methods, for opaque and per-surface alpha
  114.  */
  115.  
  116. #define OPAQUE_BLIT(to, from, length, bpp, alpha)    \
  117.     SDL_memcpy(to, from, (unsigned)(length * bpp))
  118.  
  119. /*
  120.  * For 32bpp pixels on the form 0x00rrggbb:
  121.  * If we treat the middle component separately, we can process the two
  122.  * remaining in parallel. This is safe to do because of the gap to the left
  123.  * of each component, so the bits from the multiplication don't collide.
  124.  * This can be used for any RGB permutation of course.
  125.  */
  126. #define ALPHA_BLIT32_888(to, from, length, bpp, alpha)        \
  127.     do {                            \
  128.         int i;                            \
  129.     Uint32 *src = (Uint32 *)(from);                \
  130.     Uint32 *dst = (Uint32 *)(to);                \
  131.     for(i = 0; i < (int)(length); i++) {            \
  132.         Uint32 s = *src++;                    \
  133.         Uint32 d = *dst;                    \
  134.         Uint32 s1 = s & 0xff00ff;                \
  135.         Uint32 d1 = d & 0xff00ff;                \
  136.         d1 = (d1 + ((s1 - d1) * alpha >> 8)) & 0xff00ff;    \
  137.         s &= 0xff00;                    \
  138.         d &= 0xff00;                    \
  139.         d = (d + ((s - d) * alpha >> 8)) & 0xff00;        \
  140.         *dst++ = d1 | d;                    \
  141.     }                            \
  142.     } while(0)
  143.  
  144. /*
  145.  * For 16bpp pixels we can go a step further: put the middle component
  146.  * in the high 16 bits of a 32 bit word, and process all three RGB
  147.  * components at the same time. Since the smallest gap is here just
  148.  * 5 bits, we have to scale alpha down to 5 bits as well.
  149.  */
  150. #define ALPHA_BLIT16_565(to, from, length, bpp, alpha)    \
  151.     do {                        \
  152.         int i;                        \
  153.     Uint16 *src = (Uint16 *)(from);            \
  154.     Uint16 *dst = (Uint16 *)(to);            \
  155.     for(i = 0; i < (int)(length); i++) {        \
  156.         Uint32 s = *src++;                \
  157.         Uint32 d = *dst;                \
  158.         s = (s | s << 16) & 0x07e0f81f;        \
  159.         d = (d | d << 16) & 0x07e0f81f;        \
  160.         d += (s - d) * alpha >> 5;            \
  161.         d &= 0x07e0f81f;                \
  162.         *dst++ = d | d >> 16;            \
  163.     }                        \
  164.     } while(0)
  165.  
  166. #define ALPHA_BLIT16_555(to, from, length, bpp, alpha)    \
  167.     do {                        \
  168.         int i;                        \
  169.     Uint16 *src = (Uint16 *)(from);            \
  170.     Uint16 *dst = (Uint16 *)(to);            \
  171.     for(i = 0; i < (int)(length); i++) {        \
  172.         Uint32 s = *src++;                \
  173.         Uint32 d = *dst;                \
  174.         s = (s | s << 16) & 0x03e07c1f;        \
  175.         d = (d | d << 16) & 0x03e07c1f;        \
  176.         d += (s - d) * alpha >> 5;            \
  177.         d &= 0x03e07c1f;                \
  178.         *dst++ = d | d >> 16;            \
  179.     }                        \
  180.     } while(0)
  181.  
  182. /*
  183.  * The general slow catch-all function, for remaining depths and formats
  184.  */
  185. #define ALPHA_BLIT_ANY(to, from, length, bpp, alpha)            \
  186.     do {                                \
  187.         int i;                                \
  188.     Uint8 *src = from;                        \
  189.     Uint8 *dst = to;                        \
  190.     for(i = 0; i < (int)(length); i++) {                \
  191.         Uint32 s, d;                        \
  192.         unsigned rs, gs, bs, rd, gd, bd;                \
  193.         switch(bpp) {                        \
  194.         case 2:                            \
  195.         s = *(Uint16 *)src;                    \
  196.         d = *(Uint16 *)dst;                    \
  197.         break;                            \
  198.         case 3:                            \
  199.         if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {            \
  200.             s = (src[0] << 16) | (src[1] << 8) | src[2];    \
  201.             d = (dst[0] << 16) | (dst[1] << 8) | dst[2];    \
  202.         } else {                        \
  203.             s = (src[2] << 16) | (src[1] << 8) | src[0];    \
  204.             d = (dst[2] << 16) | (dst[1] << 8) | dst[0];    \
  205.         }                            \
  206.         break;                            \
  207.         case 4:                            \
  208.         s = *(Uint32 *)src;                    \
  209.         d = *(Uint32 *)dst;                    \
  210.         break;                            \
  211.         }                                \
  212.         RGB_FROM_PIXEL(s, fmt, rs, gs, bs);                \
  213.         RGB_FROM_PIXEL(d, fmt, rd, gd, bd);                \
  214.         rd += (rs - rd) * alpha >> 8;                \
  215.         gd += (gs - gd) * alpha >> 8;                \
  216.         bd += (bs - bd) * alpha >> 8;                \
  217.         PIXEL_FROM_RGB(d, fmt, rd, gd, bd);                \
  218.         switch(bpp) {                        \
  219.         case 2:                            \
  220.         *(Uint16 *)dst = d;                    \
  221.         break;                            \
  222.         case 3:                            \
  223.         if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {            \
  224.             dst[0] = d >> 16;                    \
  225.             dst[1] = d >> 8;                    \
  226.             dst[2] = d;                        \
  227.         } else {                        \
  228.             dst[0] = d;                        \
  229.             dst[1] = d >> 8;                    \
  230.             dst[2] = d >> 16;                    \
  231.         }                            \
  232.         break;                            \
  233.         case 4:                            \
  234.         *(Uint32 *)dst = d;                    \
  235.         break;                            \
  236.         }                                \
  237.         src += bpp;                            \
  238.         dst += bpp;                            \
  239.     }                                \
  240.     } while(0)
  241.  
  242.  
  243. /*
  244.  * Special case: 50% alpha (alpha=128)
  245.  * This is treated specially because it can be optimized very well, and
  246.  * since it is good for many cases of semi-translucency.
  247.  * The theory is to do all three components at the same time:
  248.  * First zero the lowest bit of each component, which gives us room to
  249.  * add them. Then shift right and add the sum of the lowest bits.
  250.  */
  251. #define ALPHA_BLIT32_888_50(to, from, length, bpp, alpha)        \
  252.     do {                                \
  253.         int i;                                \
  254.     Uint32 *src = (Uint32 *)(from);                    \
  255.     Uint32 *dst = (Uint32 *)(to);                    \
  256.     for(i = 0; i < (int)(length); i++) {                \
  257.         Uint32 s = *src++;                        \
  258.         Uint32 d = *dst;                        \
  259.         *dst++ = (((s & 0x00fefefe) + (d & 0x00fefefe)) >> 1)    \
  260.              + (s & d & 0x00010101);                \
  261.     }                                \
  262.     } while(0)
  263.  
  264. /*
  265.  * For 16bpp, we can actually blend two pixels in parallel, if we take
  266.  * care to shift before we add, not after.
  267.  */
  268.  
  269. /* helper: blend a single 16 bit pixel at 50% */
  270. #define BLEND16_50(dst, src, mask)            \
  271.     do {                        \
  272.         Uint32 s = *src++;                \
  273.     Uint32 d = *dst;                \
  274.     *dst++ = (((s & mask) + (d & mask)) >> 1)    \
  275.              + (s & d & (~mask & 0xffff));        \
  276.     } while(0)
  277.  
  278. /* basic 16bpp blender. mask is the pixels to keep when adding. */
  279. #define ALPHA_BLIT16_50(to, from, length, bpp, alpha, mask)        \
  280.     do {                                \
  281.     unsigned n = (length);                        \
  282.     Uint16 *src = (Uint16 *)(from);                    \
  283.     Uint16 *dst = (Uint16 *)(to);                    \
  284.     if(((unsigned long)src ^ (unsigned long)dst) & 3) {        \
  285.         /* source and destination not in phase, blit one by one */    \
  286.         while(n--)                            \
  287.         BLEND16_50(dst, src, mask);                \
  288.     } else {                            \
  289.         if((unsigned long)src & 3) {                \
  290.         /* first odd pixel */                    \
  291.         BLEND16_50(dst, src, mask);                \
  292.         n--;                            \
  293.         }                                \
  294.         for(; n > 1; n -= 2) {                    \
  295.         Uint32 s = *(Uint32 *)src;                \
  296.         Uint32 d = *(Uint32 *)dst;                \
  297.         *(Uint32 *)dst = ((s & (mask | mask << 16)) >> 1)    \
  298.                        + ((d & (mask | mask << 16)) >> 1)    \
  299.                        + (s & d & (~(mask | mask << 16)));    \
  300.         src += 2;                        \
  301.         dst += 2;                        \
  302.         }                                \
  303.         if(n)                            \
  304.         BLEND16_50(dst, src, mask); /* last odd pixel */    \
  305.     }                                \
  306.     } while(0)
  307.  
  308. #define ALPHA_BLIT16_565_50(to, from, length, bpp, alpha)    \
  309.     ALPHA_BLIT16_50(to, from, length, bpp, alpha, 0xf7de)
  310.  
  311. #define ALPHA_BLIT16_555_50(to, from, length, bpp, alpha)    \
  312.     ALPHA_BLIT16_50(to, from, length, bpp, alpha, 0xfbde)
  313.  
  314.  
  315. #define CHOOSE_BLIT(blitter, alpha, fmt)                \
  316.     do {                                \
  317.         if(alpha == 255) {                        \
  318.         switch(fmt->BytesPerPixel) {                \
  319.         case 1: blitter(1, Uint8, OPAQUE_BLIT); break;        \
  320.         case 2: blitter(2, Uint8, OPAQUE_BLIT); break;        \
  321.         case 3: blitter(3, Uint8, OPAQUE_BLIT); break;        \
  322.         case 4: blitter(4, Uint16, OPAQUE_BLIT); break;        \
  323.         }                                \
  324.     } else {                            \
  325.         switch(fmt->BytesPerPixel) {                \
  326.         case 1:                            \
  327.         /* No 8bpp alpha blitting */                \
  328.         break;                            \
  329.                                     \
  330.         case 2:                            \
  331.         switch(fmt->Rmask | fmt->Gmask | fmt->Bmask) {        \
  332.         case 0xffff:                        \
  333.             if(fmt->Gmask == 0x07e0                \
  334.                || fmt->Rmask == 0x07e0                \
  335.                || fmt->Bmask == 0x07e0) {            \
  336.             if(alpha == 128)                \
  337.                 blitter(2, Uint8, ALPHA_BLIT16_565_50);    \
  338.             else {                        \
  339.                 alpha >>= 3; /* use 5 bit alpha */        \
  340.                 blitter(2, Uint8, ALPHA_BLIT16_565);    \
  341.             }                        \
  342.             } else                        \
  343.             goto general16;                    \
  344.             break;                        \
  345.                                     \
  346.         case 0x7fff:                        \
  347.             if(fmt->Gmask == 0x03e0                \
  348.                || fmt->Rmask == 0x03e0                \
  349.                || fmt->Bmask == 0x03e0) {            \
  350.             if(alpha == 128)                \
  351.                 blitter(2, Uint8, ALPHA_BLIT16_555_50);    \
  352.             else {                        \
  353.                 alpha >>= 3; /* use 5 bit alpha */        \
  354.                 blitter(2, Uint8, ALPHA_BLIT16_555);    \
  355.             }                        \
  356.             break;                        \
  357.             }                            \
  358.             /* fallthrough */                    \
  359.                                     \
  360.         default:                        \
  361.         general16:                        \
  362.             blitter(2, Uint8, ALPHA_BLIT_ANY);            \
  363.         }                            \
  364.         break;                            \
  365.                                     \
  366.         case 3:                            \
  367.         blitter(3, Uint8, ALPHA_BLIT_ANY);            \
  368.         break;                            \
  369.                                     \
  370.         case 4:                            \
  371.         if((fmt->Rmask | fmt->Gmask | fmt->Bmask) == 0x00ffffff    \
  372.            && (fmt->Gmask == 0xff00 || fmt->Rmask == 0xff00    \
  373.                || fmt->Bmask == 0xff00)) {            \
  374.             if(alpha == 128)                    \
  375.             blitter(4, Uint16, ALPHA_BLIT32_888_50);    \
  376.             else                        \
  377.             blitter(4, Uint16, ALPHA_BLIT32_888);        \
  378.         } else                            \
  379.             blitter(4, Uint16, ALPHA_BLIT_ANY);            \
  380.         break;                            \
  381.         }                                \
  382.     }                                \
  383.     } while(0)
  384.  
  385.  
  386. /*
  387.  * This takes care of the case when the surface is clipped on the left and/or
  388.  * right. Top clipping has already been taken care of.
  389.  */
  390. static void RLEClipBlit(int w, Uint8 *srcbuf, SDL_Surface *dst,
  391.             Uint8 *dstbuf, SDL_Rect *srcrect, unsigned alpha)
  392. {
  393.     SDL_PixelFormat *fmt = dst->format;
  394.  
  395. #define RLECLIPBLIT(bpp, Type, do_blit)                       \
  396.     do {                                   \
  397.     int linecount = srcrect->h;                       \
  398.     int ofs = 0;                               \
  399.     int left = srcrect->x;                           \
  400.     int right = left + srcrect->w;                       \
  401.     dstbuf -= left * bpp;                           \
  402.     for(;;) {                               \
  403.         int run;                               \
  404.         ofs += *(Type *)srcbuf;                       \
  405.         run = ((Type *)srcbuf)[1];                       \
  406.         srcbuf += 2 * sizeof(Type);                       \
  407.         if(run) {                               \
  408.         /* clip to left and right borders */               \
  409.         if(ofs < right) {                       \
  410.             int start = 0;                       \
  411.             int len = run;                       \
  412.             int startcol;                       \
  413.             if(left - ofs > 0) {                   \
  414.             start = left - ofs;                   \
  415.             len -= start;                       \
  416.             if(len <= 0)                       \
  417.                 goto nocopy ## bpp ## do_blit;           \
  418.             }                               \
  419.             startcol = ofs + start;                   \
  420.             if(len > right - startcol)                   \
  421.             len = right - startcol;                   \
  422.             do_blit(dstbuf + startcol * bpp, srcbuf + start * bpp, \
  423.                 len, bpp, alpha);                   \
  424.         }                               \
  425.         nocopy ## bpp ## do_blit:                       \
  426.         srcbuf += run * bpp;                       \
  427.         ofs += run;                           \
  428.         } else if(!ofs)                           \
  429.         break;                               \
  430.         if(ofs == w) {                           \
  431.         ofs = 0;                           \
  432.         dstbuf += dst->pitch;                       \
  433.         if(!--linecount)                       \
  434.             break;                           \
  435.         }                                   \
  436.     }                                   \
  437.     } while(0)
  438.  
  439.     CHOOSE_BLIT(RLECLIPBLIT, alpha, fmt);
  440.  
  441. #undef RLECLIPBLIT
  442.  
  443. }
  444.  
  445.  
  446. /* blit a colorkeyed RLE surface */
  447. int SDL_RLEBlit(SDL_Surface *src, SDL_Rect *srcrect,
  448.         SDL_Surface *dst, SDL_Rect *dstrect)
  449. {
  450.     Uint8 *dstbuf;
  451.     Uint8 *srcbuf;
  452.     int x, y;
  453.     int w = src->w;
  454.     unsigned alpha;
  455.  
  456.     /* Lock the destination if necessary */
  457.     if ( dst->flags & (SDL_HWSURFACE|SDL_ASYNCBLIT) ) {
  458.         SDL_VideoDevice *video = current_video;
  459.         SDL_VideoDevice *this  = current_video;
  460.         if ( video->LockHWSurface(this, dst) < 0 ) {
  461.             return(-1);
  462.         }
  463.     }
  464.  
  465.     /* Set up the source and destination pointers */
  466.     x = dstrect->x;
  467.     y = dstrect->y;
  468.     dstbuf = (Uint8 *)dst->pixels + dst->offset
  469.              + y * dst->pitch + x * src->format->BytesPerPixel;
  470.     srcbuf = (Uint8 *)src->map->sw_data->aux_data;
  471.  
  472.     {
  473.         /* skip lines at the top if neccessary */
  474.         int vskip = srcrect->y;
  475.         int ofs = 0;
  476.         if(vskip) {
  477.  
  478. #define RLESKIP(bpp, Type)            \
  479.         for(;;) {            \
  480.             int run;            \
  481.             ofs += *(Type *)srcbuf;    \
  482.             run = ((Type *)srcbuf)[1];    \
  483.             srcbuf += sizeof(Type) * 2;    \
  484.             if(run) {            \
  485.             srcbuf += run * bpp;    \
  486.             ofs += run;        \
  487.             } else if(!ofs)        \
  488.             goto done;        \
  489.             if(ofs == w) {        \
  490.             ofs = 0;        \
  491.             if(!--vskip)        \
  492.                 break;        \
  493.             }                \
  494.         }
  495.  
  496.         switch(src->format->BytesPerPixel) {
  497.         case 1: RLESKIP(1, Uint8); break;
  498.         case 2: RLESKIP(2, Uint8); break;
  499.         case 3: RLESKIP(3, Uint8); break;
  500.         case 4: RLESKIP(4, Uint16); break;
  501.         }
  502.  
  503. #undef RLESKIP
  504.  
  505.         }
  506.     }
  507.  
  508.     alpha = (src->flags & SDL_SRCALPHA) == SDL_SRCALPHA
  509.             ? src->format->alpha : 255;
  510.     /* if left or right edge clipping needed, call clip blit */
  511.     if ( srcrect->x || srcrect->w != src->w ) {
  512.         RLEClipBlit(w, srcbuf, dst, dstbuf, srcrect, alpha);
  513.     } else {
  514.         SDL_PixelFormat *fmt = src->format;
  515.  
  516. #define RLEBLIT(bpp, Type, do_blit)                          \
  517.         do {                                  \
  518.         int linecount = srcrect->h;                      \
  519.         int ofs = 0;                              \
  520.         for(;;) {                              \
  521.             unsigned run;                          \
  522.             ofs += *(Type *)srcbuf;                      \
  523.             run = ((Type *)srcbuf)[1];                      \
  524.             srcbuf += 2 * sizeof(Type);                      \
  525.             if(run) {                              \
  526.             do_blit(dstbuf + ofs * bpp, srcbuf, run, bpp, alpha); \
  527.             srcbuf += run * bpp;                      \
  528.             ofs += run;                          \
  529.             } else if(!ofs)                          \
  530.             break;                              \
  531.             if(ofs == w) {                          \
  532.             ofs = 0;                          \
  533.             dstbuf += dst->pitch;                      \
  534.             if(!--linecount)                      \
  535.                 break;                          \
  536.             }                                  \
  537.         }                                  \
  538.         } while(0)
  539.  
  540.         CHOOSE_BLIT(RLEBLIT, alpha, fmt);
  541.  
  542. #undef RLEBLIT
  543.     }
  544.  
  545. done:
  546.     /* Unlock the destination if necessary */
  547.     if ( dst->flags & (SDL_HWSURFACE|SDL_ASYNCBLIT) ) {
  548.         SDL_VideoDevice *video = current_video;
  549.         SDL_VideoDevice *this  = current_video;
  550.         video->UnlockHWSurface(this, dst);
  551.     }
  552.     return(0);
  553. }
  554.  
  555. #undef OPAQUE_BLIT
  556.  
  557. /*
  558.  * Per-pixel blitting macros for translucent pixels:
  559.  * These use the same techniques as the per-surface blitting macros
  560.  */
  561.  
  562. /*
  563.  * For 32bpp pixels, we have made sure the alpha is stored in the top
  564.  * 8 bits, so proceed as usual
  565.  */
  566. #define BLIT_TRANSL_888(src, dst)                \
  567.     do {                            \
  568.         Uint32 s = src;                        \
  569.     Uint32 d = dst;                        \
  570.     unsigned alpha = s >> 24;                \
  571.     Uint32 s1 = s & 0xff00ff;                \
  572.     Uint32 d1 = d & 0xff00ff;                \
  573.     d1 = (d1 + ((s1 - d1) * alpha >> 8)) & 0xff00ff;    \
  574.     s &= 0xff00;                        \
  575.     d &= 0xff00;                        \
  576.     d = (d + ((s - d) * alpha >> 8)) & 0xff00;        \
  577.     dst = d1 | d;                        \
  578.     } while(0)
  579.  
  580. /*
  581.  * For 16bpp pixels, we have stored the 5 most significant alpha bits in
  582.  * bits 5-10. As before, we can process all 3 RGB components at the same time.
  583.  */
  584. #define BLIT_TRANSL_565(src, dst)        \
  585.     do {                    \
  586.         Uint32 s = src;                \
  587.     Uint32 d = dst;                \
  588.     unsigned alpha = (s & 0x3e0) >> 5;    \
  589.     s &= 0x07e0f81f;            \
  590.     d = (d | d << 16) & 0x07e0f81f;        \
  591.     d += (s - d) * alpha >> 5;        \
  592.     d &= 0x07e0f81f;            \
  593.     dst = d | d >> 16;            \
  594.     } while(0)
  595.  
  596. #define BLIT_TRANSL_555(src, dst)        \
  597.     do {                    \
  598.         Uint32 s = src;                \
  599.     Uint32 d = dst;                \
  600.     unsigned alpha = (s & 0x3e0) >> 5;    \
  601.     s &= 0x03e07c1f;            \
  602.     d = (d | d << 16) & 0x03e07c1f;        \
  603.     d += (s - d) * alpha >> 5;        \
  604.     d &= 0x03e07c1f;            \
  605.     dst = d | d >> 16;            \
  606.     } while(0)
  607.  
  608. /* used to save the destination format in the encoding. Designed to be
  609.    macro-compatible with SDL_PixelFormat but without the unneeded fields */
  610. typedef struct {
  611.         Uint8  BytesPerPixel;
  612.     Uint8  Rloss;
  613.     Uint8  Gloss;
  614.     Uint8  Bloss;
  615.     Uint8  Rshift;
  616.     Uint8  Gshift;
  617.     Uint8  Bshift;
  618.     Uint8  Ashift;
  619.     Uint32 Rmask;
  620.     Uint32 Gmask;
  621.     Uint32 Bmask;
  622.     Uint32 Amask;
  623. } RLEDestFormat;
  624.  
  625. /* blit a pixel-alpha RLE surface clipped at the right and/or left edges */
  626. static void RLEAlphaClipBlit(int w, Uint8 *srcbuf, SDL_Surface *dst,
  627.                  Uint8 *dstbuf, SDL_Rect *srcrect)
  628. {
  629.     SDL_PixelFormat *df = dst->format;
  630.     /*
  631.      * clipped blitter: Ptype is the destination pixel type,
  632.      * Ctype the translucent count type, and do_blend the macro
  633.      * to blend one pixel.
  634.      */
  635. #define RLEALPHACLIPBLIT(Ptype, Ctype, do_blend)              \
  636.     do {                                  \
  637.     int linecount = srcrect->h;                      \
  638.     int left = srcrect->x;                          \
  639.     int right = left + srcrect->w;                      \
  640.     dstbuf -= left * sizeof(Ptype);                      \
  641.     do {                                  \
  642.         int ofs = 0;                          \
  643.         /* blit opaque pixels on one line */              \
  644.         do {                              \
  645.         unsigned run;                          \
  646.         ofs += ((Ctype *)srcbuf)[0];                  \
  647.         run = ((Ctype *)srcbuf)[1];                  \
  648.         srcbuf += 2 * sizeof(Ctype);                  \
  649.         if(run) {                          \
  650.             /* clip to left and right borders */          \
  651.             int cofs = ofs;                      \
  652.             int crun = run;                      \
  653.             if(left - cofs > 0) {                  \
  654.             crun -= left - cofs;                  \
  655.             cofs = left;                      \
  656.             }                              \
  657.             if(crun > right - cofs)                  \
  658.             crun = right - cofs;                  \
  659.             if(crun > 0)                      \
  660.             SDL_memcpy(dstbuf + cofs * sizeof(Ptype),      \
  661.                    srcbuf + (cofs - ofs) * sizeof(Ptype), \
  662.                    (unsigned)crun * sizeof(Ptype));      \
  663.             srcbuf += run * sizeof(Ptype);              \
  664.             ofs += run;                          \
  665.         } else if(!ofs)                          \
  666.             return;                          \
  667.         } while(ofs < w);                          \
  668.         /* skip padding if necessary */                  \
  669.         if(sizeof(Ptype) == 2)                      \
  670.         srcbuf += (unsigned long)srcbuf & 2;              \
  671.         /* blit translucent pixels on the same line */          \
  672.         ofs = 0;                              \
  673.         do {                              \
  674.         unsigned run;                          \
  675.         ofs += ((Uint16 *)srcbuf)[0];                  \
  676.         run = ((Uint16 *)srcbuf)[1];                  \
  677.         srcbuf += 4;                          \
  678.         if(run) {                          \
  679.             /* clip to left and right borders */          \
  680.             int cofs = ofs;                      \
  681.             int crun = run;                      \
  682.             if(left - cofs > 0) {                  \
  683.             crun -= left - cofs;                  \
  684.             cofs = left;                      \
  685.             }                              \
  686.             if(crun > right - cofs)                  \
  687.             crun = right - cofs;                  \
  688.             if(crun > 0) {                      \
  689.             Ptype *dst = (Ptype *)dstbuf + cofs;          \
  690.             Uint32 *src = (Uint32 *)srcbuf + (cofs - ofs);      \
  691.             int i;                          \
  692.             for(i = 0; i < crun; i++)              \
  693.                 do_blend(src[i], dst[i]);              \
  694.             }                              \
  695.             srcbuf += run * 4;                      \
  696.             ofs += run;                          \
  697.         }                              \
  698.         } while(ofs < w);                          \
  699.         dstbuf += dst->pitch;                      \
  700.     } while(--linecount);                          \
  701.     } while(0)
  702.  
  703.     switch(df->BytesPerPixel) {
  704.     case 2:
  705.     if(df->Gmask == 0x07e0 || df->Rmask == 0x07e0
  706.        || df->Bmask == 0x07e0)
  707.         RLEALPHACLIPBLIT(Uint16, Uint8, BLIT_TRANSL_565);
  708.     else
  709.         RLEALPHACLIPBLIT(Uint16, Uint8, BLIT_TRANSL_555);
  710.     break;
  711.     case 4:
  712.     RLEALPHACLIPBLIT(Uint32, Uint16, BLIT_TRANSL_888);
  713.     break;
  714.     }
  715. }
  716.  
  717. /* blit a pixel-alpha RLE surface */
  718. int SDL_RLEAlphaBlit(SDL_Surface *src, SDL_Rect *srcrect,
  719.              SDL_Surface *dst, SDL_Rect *dstrect)
  720. {
  721.     int x, y;
  722.     int w = src->w;
  723.     Uint8 *srcbuf, *dstbuf;
  724.     SDL_PixelFormat *df = dst->format;
  725.  
  726.     /* Lock the destination if necessary */
  727.     if(dst->flags & (SDL_HWSURFACE|SDL_ASYNCBLIT)) {
  728.     SDL_VideoDevice *video = current_video;
  729.     SDL_VideoDevice *this  = current_video;
  730.     if(video->LockHWSurface(this, dst) < 0) {
  731.         return -1;
  732.     }
  733.     }
  734.  
  735.     x = dstrect->x;
  736.     y = dstrect->y;
  737.     dstbuf = (Uint8 *)dst->pixels + dst->offset
  738.          + y * dst->pitch + x * df->BytesPerPixel;
  739.     srcbuf = (Uint8 *)src->map->sw_data->aux_data + sizeof(RLEDestFormat);
  740.  
  741.     {
  742.     /* skip lines at the top if necessary */
  743.     int vskip = srcrect->y;
  744.     if(vskip) {
  745.         int ofs;
  746.         if(df->BytesPerPixel == 2) {
  747.         /* the 16/32 interleaved format */
  748.         do {
  749.             /* skip opaque line */
  750.             ofs = 0;
  751.             do {
  752.             int run;
  753.             ofs += srcbuf[0];
  754.             run = srcbuf[1];
  755.             srcbuf += 2;
  756.             if(run) {
  757.                 srcbuf += 2 * run;
  758.                 ofs += run;
  759.             } else if(!ofs)
  760.                 goto done;
  761.             } while(ofs < w);
  762.  
  763.             /* skip padding */
  764.             srcbuf += (unsigned long)srcbuf & 2;
  765.  
  766.             /* skip translucent line */
  767.             ofs = 0;
  768.             do {
  769.             int run;
  770.             ofs += ((Uint16 *)srcbuf)[0];
  771.             run = ((Uint16 *)srcbuf)[1];
  772.             srcbuf += 4 * (run + 1);
  773.             ofs += run;
  774.             } while(ofs < w);
  775.         } while(--vskip);
  776.         } else {
  777.         /* the 32/32 interleaved format */
  778.         vskip <<= 1;    /* opaque and translucent have same format */
  779.         do {
  780.             ofs = 0;
  781.             do {
  782.             int run;
  783.             ofs += ((Uint16 *)srcbuf)[0];
  784.             run = ((Uint16 *)srcbuf)[1];
  785.             srcbuf += 4;
  786.             if(run) {
  787.                 srcbuf += 4 * run;
  788.                 ofs += run;
  789.             } else if(!ofs)
  790.                 goto done;
  791.             } while(ofs < w);
  792.         } while(--vskip);
  793.         }
  794.     }
  795.     }
  796.  
  797.     /* if left or right edge clipping needed, call clip blit */
  798.     if(srcrect->x || srcrect->w != src->w) {
  799.     RLEAlphaClipBlit(w, srcbuf, dst, dstbuf, srcrect);
  800.     } else {
  801.  
  802.     /*
  803.      * non-clipped blitter. Ptype is the destination pixel type,
  804.      * Ctype the translucent count type, and do_blend the
  805.      * macro to blend one pixel.
  806.      */
  807. #define RLEALPHABLIT(Ptype, Ctype, do_blend)                 \
  808.     do {                                 \
  809.         int linecount = srcrect->h;                     \
  810.         do {                             \
  811.         int ofs = 0;                         \
  812.         /* blit opaque pixels on one line */             \
  813.         do {                             \
  814.             unsigned run;                     \
  815.             ofs += ((Ctype *)srcbuf)[0];             \
  816.             run = ((Ctype *)srcbuf)[1];                 \
  817.             srcbuf += 2 * sizeof(Ctype);             \
  818.             if(run) {                         \
  819.             SDL_memcpy(dstbuf + ofs * sizeof(Ptype), srcbuf, \
  820.                    run * sizeof(Ptype));         \
  821.             srcbuf += run * sizeof(Ptype);             \
  822.             ofs += run;                     \
  823.             } else if(!ofs)                     \
  824.             goto done;                     \
  825.         } while(ofs < w);                     \
  826.         /* skip padding if necessary */                 \
  827.         if(sizeof(Ptype) == 2)                     \
  828.             srcbuf += (unsigned long)srcbuf & 2;         \
  829.         /* blit translucent pixels on the same line */         \
  830.         ofs = 0;                         \
  831.         do {                             \
  832.             unsigned run;                     \
  833.             ofs += ((Uint16 *)srcbuf)[0];             \
  834.             run = ((Uint16 *)srcbuf)[1];             \
  835.             srcbuf += 4;                     \
  836.             if(run) {                         \
  837.             Ptype *dst = (Ptype *)dstbuf + ofs;         \
  838.             unsigned i;                     \
  839.             for(i = 0; i < run; i++) {             \
  840.                 Uint32 src = *(Uint32 *)srcbuf;         \
  841.                 do_blend(src, *dst);             \
  842.                 srcbuf += 4;                 \
  843.                 dst++;                     \
  844.             }                         \
  845.             ofs += run;                     \
  846.             }                             \
  847.         } while(ofs < w);                     \
  848.         dstbuf += dst->pitch;                     \
  849.         } while(--linecount);                     \
  850.     } while(0)
  851.  
  852.     switch(df->BytesPerPixel) {
  853.     case 2:
  854.         if(df->Gmask == 0x07e0 || df->Rmask == 0x07e0
  855.            || df->Bmask == 0x07e0)
  856.         RLEALPHABLIT(Uint16, Uint8, BLIT_TRANSL_565);
  857.         else
  858.         RLEALPHABLIT(Uint16, Uint8, BLIT_TRANSL_555);
  859.         break;
  860.     case 4:
  861.         RLEALPHABLIT(Uint32, Uint16, BLIT_TRANSL_888);
  862.         break;
  863.     }
  864.     }
  865.  
  866.  done:
  867.     /* Unlock the destination if necessary */
  868.     if(dst->flags & (SDL_HWSURFACE|SDL_ASYNCBLIT)) {
  869.     SDL_VideoDevice *video = current_video;
  870.     SDL_VideoDevice *this  = current_video;
  871.     video->UnlockHWSurface(this, dst);
  872.     }
  873.     return 0;
  874. }
  875.  
  876. /*
  877.  * Auxiliary functions:
  878.  * The encoding functions take 32bpp rgb + a, and
  879.  * return the number of bytes copied to the destination.
  880.  * The decoding functions copy to 32bpp rgb + a, and
  881.  * return the number of bytes copied from the source.
  882.  * These are only used in the encoder and un-RLE code and are therefore not
  883.  * highly optimised.
  884.  */
  885.  
  886. /* encode 32bpp rgb + a into 16bpp rgb, losing alpha */
  887. static int copy_opaque_16(void *dst, Uint32 *src, int n,
  888.               SDL_PixelFormat *sfmt, SDL_PixelFormat *dfmt)
  889. {
  890.     int i;
  891.     Uint16 *d = dst;
  892.     for(i = 0; i < n; i++) {
  893.     unsigned r, g, b;
  894.     RGB_FROM_PIXEL(*src, sfmt, r, g, b);
  895.     PIXEL_FROM_RGB(*d, dfmt, r, g, b);
  896.     src++;
  897.     d++;
  898.     }
  899.     return n * 2;
  900. }
  901.  
  902. /* decode opaque pixels from 16bpp to 32bpp rgb + a */
  903. static int uncopy_opaque_16(Uint32 *dst, void *src, int n,
  904.                 RLEDestFormat *sfmt, SDL_PixelFormat *dfmt)
  905. {
  906.     int i;
  907.     Uint16 *s = src;
  908.     unsigned alpha = dfmt->Amask ? 255 : 0;
  909.     for(i = 0; i < n; i++) {
  910.     unsigned r, g, b;
  911.     RGB_FROM_PIXEL(*s, sfmt, r, g, b);
  912.     PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, alpha);
  913.     s++;
  914.     dst++;
  915.     }
  916.     return n * 2;
  917. }
  918.  
  919.  
  920.  
  921. /* encode 32bpp rgb + a into 32bpp G0RAB format for blitting into 565 */
  922. static int copy_transl_565(void *dst, Uint32 *src, int n,
  923.                SDL_PixelFormat *sfmt, SDL_PixelFormat *dfmt)
  924. {
  925.     int i;
  926.     Uint32 *d = dst;
  927.     for(i = 0; i < n; i++) {
  928.     unsigned r, g, b, a;
  929.     Uint16 pix;
  930.     RGBA_FROM_8888(*src, sfmt, r, g, b, a);
  931.     PIXEL_FROM_RGB(pix, dfmt, r, g, b);
  932.     *d = ((pix & 0x7e0) << 16) | (pix & 0xf81f) | ((a << 2) & 0x7e0);
  933.     src++;
  934.     d++;
  935.     }
  936.     return n * 4;
  937. }
  938.  
  939. /* encode 32bpp rgb + a into 32bpp G0RAB format for blitting into 555 */
  940. static int copy_transl_555(void *dst, Uint32 *src, int n,
  941.                SDL_PixelFormat *sfmt, SDL_PixelFormat *dfmt)
  942. {
  943.     int i;
  944.     Uint32 *d = dst;
  945.     for(i = 0; i < n; i++) {
  946.     unsigned r, g, b, a;
  947.     Uint16 pix;
  948.     RGBA_FROM_8888(*src, sfmt, r, g, b, a);
  949.     PIXEL_FROM_RGB(pix, dfmt, r, g, b);
  950.     *d = ((pix & 0x3e0) << 16) | (pix & 0xfc1f) | ((a << 2) & 0x3e0);
  951.     src++;
  952.     d++;
  953.     }
  954.     return n * 4;
  955. }
  956.  
  957. /* decode translucent pixels from 32bpp GORAB to 32bpp rgb + a */
  958. static int uncopy_transl_16(Uint32 *dst, void *src, int n,
  959.                 RLEDestFormat *sfmt, SDL_PixelFormat *dfmt)
  960. {
  961.     int i;
  962.     Uint32 *s = src;
  963.     for(i = 0; i < n; i++) {
  964.     unsigned r, g, b, a;
  965.     Uint32 pix = *s++;
  966.     a = (pix & 0x3e0) >> 2;
  967.     pix = (pix & ~0x3e0) | pix >> 16;
  968.     RGB_FROM_PIXEL(pix, sfmt, r, g, b);
  969.     PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, a);
  970.     dst++;
  971.     }
  972.     return n * 4;
  973. }
  974.  
  975. /* encode 32bpp rgba into 32bpp rgba, keeping alpha (dual purpose) */
  976. static int copy_32(void *dst, Uint32 *src, int n,
  977.            SDL_PixelFormat *sfmt, SDL_PixelFormat *dfmt)
  978. {
  979.     int i;
  980.     Uint32 *d = dst;
  981.     for(i = 0; i < n; i++) {
  982.     unsigned r, g, b, a;
  983.     Uint32 pixel;
  984.     RGBA_FROM_8888(*src, sfmt, r, g, b, a);
  985.     PIXEL_FROM_RGB(pixel, dfmt, r, g, b);
  986.     *d++ = pixel | a << 24;
  987.     src++;
  988.     }
  989.     return n * 4;
  990. }
  991.  
  992. /* decode 32bpp rgba into 32bpp rgba, keeping alpha (dual purpose) */
  993. static int uncopy_32(Uint32 *dst, void *src, int n,
  994.              RLEDestFormat *sfmt, SDL_PixelFormat *dfmt)
  995. {
  996.     int i;
  997.     Uint32 *s = src;
  998.     for(i = 0; i < n; i++) {
  999.     unsigned r, g, b, a;
  1000.     Uint32 pixel = *s++;
  1001.     RGB_FROM_PIXEL(pixel, sfmt, r, g, b);
  1002.     a = pixel >> 24;
  1003.     PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, a);
  1004.     dst++;
  1005.     }
  1006.     return n * 4;
  1007. }
  1008.  
  1009. #define ISOPAQUE(pixel, fmt) ((((pixel) & fmt->Amask) >> fmt->Ashift) == 255)
  1010.  
  1011. #define ISTRANSL(pixel, fmt)    \
  1012.     ((unsigned)((((pixel) & fmt->Amask) >> fmt->Ashift) - 1U) < 254U)
  1013.  
  1014. /* convert surface to be quickly alpha-blittable onto dest, if possible */
  1015. static int RLEAlphaSurface(SDL_Surface *surface)
  1016. {
  1017.     SDL_Surface *dest;
  1018.     SDL_PixelFormat *df;
  1019.     int maxsize = 0;
  1020.     int max_opaque_run;
  1021.     int max_transl_run = 65535;
  1022.     unsigned masksum;
  1023.     Uint8 *rlebuf, *dst;
  1024.     int (*copy_opaque)(void *, Uint32 *, int,
  1025.                SDL_PixelFormat *, SDL_PixelFormat *);
  1026.     int (*copy_transl)(void *, Uint32 *, int,
  1027.                SDL_PixelFormat *, SDL_PixelFormat *);
  1028.  
  1029.     dest = surface->map->dst;
  1030.     if(!dest)
  1031.     return -1;
  1032.     df = dest->format;
  1033.     if(surface->format->BitsPerPixel != 32)
  1034.     return -1;        /* only 32bpp source supported */
  1035.  
  1036.     /* find out whether the destination is one we support,
  1037.        and determine the max size of the encoded result */
  1038.     masksum = df->Rmask | df->Gmask | df->Bmask;
  1039.     switch(df->BytesPerPixel) {
  1040.     case 2:
  1041.     /* 16bpp: only support 565 and 555 formats */
  1042.     switch(masksum) {
  1043.     case 0xffff:
  1044.         if(df->Gmask == 0x07e0
  1045.            || df->Rmask == 0x07e0 || df->Bmask == 0x07e0) {
  1046.         copy_opaque = copy_opaque_16;
  1047.         copy_transl = copy_transl_565;
  1048.         } else
  1049.         return -1;
  1050.         break;
  1051.     case 0x7fff:
  1052.         if(df->Gmask == 0x03e0
  1053.            || df->Rmask == 0x03e0 || df->Bmask == 0x03e0) {
  1054.         copy_opaque = copy_opaque_16;
  1055.         copy_transl = copy_transl_555;
  1056.         } else
  1057.         return -1;
  1058.         break;
  1059.     default:
  1060.         return -1;
  1061.     }
  1062.     max_opaque_run = 255;    /* runs stored as bytes */
  1063.  
  1064.     /* worst case is alternating opaque and translucent pixels,
  1065.        with room for alignment padding between lines */
  1066.     maxsize = surface->h * (2 + (4 + 2) * (surface->w + 1)) + 2;
  1067.     break;
  1068.     case 4:
  1069.     if(masksum != 0x00ffffff)
  1070.         return -1;        /* requires unused high byte */
  1071.     copy_opaque = copy_32;
  1072.     copy_transl = copy_32;
  1073.     max_opaque_run = 255;    /* runs stored as short ints */
  1074.  
  1075.     /* worst case is alternating opaque and translucent pixels */
  1076.     maxsize = surface->h * 2 * 4 * (surface->w + 1) + 4;
  1077.     break;
  1078.     default:
  1079.     return -1;        /* anything else unsupported right now */
  1080.     }
  1081.  
  1082.     maxsize += sizeof(RLEDestFormat);
  1083.     rlebuf = (Uint8 *)malloc(maxsize);
  1084.     if(!rlebuf) {
  1085.     SDL_OutOfMemory();
  1086.     return -1;
  1087.     }
  1088.     {
  1089.     /* save the destination format so we can undo the encoding later */
  1090.     RLEDestFormat *r = (RLEDestFormat *)rlebuf;
  1091.     r->BytesPerPixel = df->BytesPerPixel;
  1092.     r->Rloss = df->Rloss;
  1093.     r->Gloss = df->Gloss;
  1094.     r->Bloss = df->Bloss;
  1095.     r->Rshift = df->Rshift;
  1096.     r->Gshift = df->Gshift;
  1097.     r->Bshift = df->Bshift;
  1098.     r->Ashift = df->Ashift;
  1099.     r->Rmask = df->Rmask;
  1100.     r->Gmask = df->Gmask;
  1101.     r->Bmask = df->Bmask;
  1102.     r->Amask = df->Amask;
  1103.     }
  1104.     dst = rlebuf + sizeof(RLEDestFormat);
  1105.  
  1106.     /* Do the actual encoding */
  1107.     {
  1108.     int x, y;
  1109.     int h = surface->h, w = surface->w;
  1110.     SDL_PixelFormat *sf = surface->format;
  1111.     Uint32 *src = (Uint32 *)((Uint8 *)surface->pixels + surface->offset);
  1112.     Uint8 *lastline = dst;    /* end of last non-blank line */
  1113.  
  1114.     /* opaque counts are 8 or 16 bits, depending on target depth */
  1115. #define ADD_OPAQUE_COUNTS(n, m)            \
  1116.     if(df->BytesPerPixel == 4) {        \
  1117.         ((Uint16 *)dst)[0] = n;        \
  1118.         ((Uint16 *)dst)[1] = m;        \
  1119.         dst += 4;                \
  1120.     } else {                \
  1121.         dst[0] = n;                \
  1122.         dst[1] = m;                \
  1123.         dst += 2;                \
  1124.     }
  1125.  
  1126.     /* translucent counts are always 16 bit */
  1127. #define ADD_TRANSL_COUNTS(n, m)        \
  1128.     (((Uint16 *)dst)[0] = n, ((Uint16 *)dst)[1] = m, dst += 4)
  1129.  
  1130.     for(y = 0; y < h; y++) {
  1131.         int runstart, skipstart;
  1132.         int blankline = 0;
  1133.         /* First encode all opaque pixels of a scan line */
  1134.         x = 0;
  1135.         do {
  1136.         int run, skip, len;
  1137.         skipstart = x;
  1138.         while(x < w && !ISOPAQUE(src[x], sf))
  1139.             x++;
  1140.         runstart = x;
  1141.         while(x < w && ISOPAQUE(src[x], sf))
  1142.             x++;
  1143.         skip = runstart - skipstart;
  1144.         if(skip == w)
  1145.             blankline = 1;
  1146.         run = x - runstart;
  1147.         while(skip > max_opaque_run) {
  1148.             ADD_OPAQUE_COUNTS(max_opaque_run, 0);
  1149.             skip -= max_opaque_run;
  1150.         }
  1151.         len = MIN(run, max_opaque_run);
  1152.         ADD_OPAQUE_COUNTS(skip, len);
  1153.         dst += copy_opaque(dst, src + runstart, len, sf, df);
  1154.         runstart += len;
  1155.         run -= len;
  1156.         while(run) {
  1157.             len = MIN(run, max_opaque_run);
  1158.             ADD_OPAQUE_COUNTS(0, len);
  1159.             dst += copy_opaque(dst, src + runstart, len, sf, df);
  1160.             runstart += len;
  1161.             run -= len;
  1162.         }
  1163.         } while(x < w);
  1164.  
  1165.         /* Make sure the next output address is 32-bit aligned */
  1166.         dst += (unsigned long)dst & 2;
  1167.  
  1168.         /* Next, encode all translucent pixels of the same scan line */
  1169.         x = 0;
  1170.         do {
  1171.         int run, skip, len;
  1172.         skipstart = x;
  1173.         while(x < w && !ISTRANSL(src[x], sf))
  1174.             x++;
  1175.         runstart = x;
  1176.         while(x < w && ISTRANSL(src[x], sf))
  1177.             x++;
  1178.         skip = runstart - skipstart;
  1179.         blankline &= (skip == w);
  1180.         run = x - runstart;
  1181.         while(skip > max_transl_run) {
  1182.             ADD_TRANSL_COUNTS(max_transl_run, 0);
  1183.             skip -= max_transl_run;
  1184.         }
  1185.         len = MIN(run, max_transl_run);
  1186.         ADD_TRANSL_COUNTS(skip, len);
  1187.         dst += copy_transl(dst, src + runstart, len, sf, df);
  1188.         runstart += len;
  1189.         run -= len;
  1190.         while(run) {
  1191.             len = MIN(run, max_transl_run);
  1192.             ADD_TRANSL_COUNTS(0, len);
  1193.             dst += copy_transl(dst, src + runstart, len, sf, df);
  1194.             runstart += len;
  1195.             run -= len;
  1196.         }
  1197.         if(!blankline)
  1198.             lastline = dst;
  1199.         } while(x < w);
  1200.  
  1201.         src += surface->pitch >> 2;
  1202.     }
  1203.     dst = lastline;        /* back up past trailing blank lines */
  1204.     ADD_OPAQUE_COUNTS(0, 0);
  1205.     }
  1206.  
  1207. #undef ADD_OPAQUE_COUNTS
  1208. #undef ADD_TRANSL_COUNTS
  1209.  
  1210.     /* Now that we have it encoded, release the original pixels */
  1211.     if((surface->flags & SDL_PREALLOC) != SDL_PREALLOC
  1212.        && (surface->flags & SDL_HWSURFACE) != SDL_HWSURFACE) {
  1213.     free( surface->pixels );
  1214.     surface->pixels = NULL;
  1215.     }
  1216.  
  1217.     /* realloc the buffer to release unused memory */
  1218.     {
  1219.     Uint8 *p = realloc(rlebuf, dst - rlebuf);
  1220.     if(!p)
  1221.         p = rlebuf;
  1222.     surface->map->sw_data->aux_data = p;
  1223.     }
  1224.  
  1225.     return 0;
  1226. }
  1227.  
  1228. static Uint32 getpix_8(Uint8 *srcbuf)
  1229. {
  1230.     return *srcbuf;
  1231. }
  1232.  
  1233. static Uint32 getpix_16(Uint8 *srcbuf)
  1234. {
  1235.     return *(Uint16 *)srcbuf;
  1236. }
  1237.  
  1238. static Uint32 getpix_24(Uint8 *srcbuf)
  1239. {
  1240.     if(SDL_BYTEORDER == SDL_LIL_ENDIAN)
  1241.     return srcbuf[0] + (srcbuf[1] << 8) + (srcbuf[2] << 16);
  1242.     else
  1243.     return (srcbuf[0] << 16) + (srcbuf[1] << 8) + srcbuf[2];
  1244. }
  1245.  
  1246. static Uint32 getpix_32(Uint8 *srcbuf)
  1247. {
  1248.     return *(Uint32 *)srcbuf;
  1249. }
  1250.  
  1251. typedef Uint32 (*getpix_func)(Uint8 *);
  1252.  
  1253. static getpix_func getpixes[4] = {
  1254.     getpix_8, getpix_16, getpix_24, getpix_32
  1255. };
  1256.  
  1257. static int RLEColorkeySurface(SDL_Surface *surface)
  1258. {
  1259.         Uint8 *rlebuf, *dst;
  1260.     int maxn;
  1261.     int y;
  1262.     Uint8 *srcbuf, *curbuf, *lastline;
  1263.     int maxsize = 0;
  1264.     int skip, run;
  1265.     int bpp = surface->format->BytesPerPixel;
  1266.     getpix_func getpix;
  1267.     Uint32 ckey, rgbmask;
  1268.     int w, h;
  1269.  
  1270.     /* calculate the worst case size for the compressed surface */
  1271.     switch(bpp) {
  1272.     case 1:
  1273.         /* worst case is alternating opaque and transparent pixels,
  1274.            starting with an opaque pixel */
  1275.         maxsize = surface->h * 3 * (surface->w / 2 + 1) + 2;
  1276.         break;
  1277.     case 2:
  1278.     case 3:
  1279.         /* worst case is solid runs, at most 255 pixels wide */
  1280.         maxsize = surface->h * (2 * (surface->w / 255 + 1)
  1281.                     + surface->w * bpp) + 2;
  1282.         break;
  1283.     case 4:
  1284.         /* worst case is solid runs, at most 65535 pixels wide */
  1285.         maxsize = surface->h * (4 * (surface->w / 65535 + 1)
  1286.                     + surface->w * 4) + 4;
  1287.         break;
  1288.     }
  1289.  
  1290.     rlebuf = (Uint8 *)malloc(maxsize);
  1291.     if ( rlebuf == NULL ) {
  1292.         SDL_OutOfMemory();
  1293.         return(-1);
  1294.     }
  1295.  
  1296.     /* Set up the conversion */
  1297.     srcbuf = (Uint8 *)surface->pixels+surface->offset;
  1298.     curbuf = srcbuf;
  1299.     maxn = bpp == 4 ? 65535 : 255;
  1300.     skip = run = 0;
  1301.     dst = rlebuf;
  1302.     rgbmask = ~surface->format->Amask;
  1303.     ckey = surface->format->colorkey & rgbmask;
  1304.     lastline = dst;
  1305.     getpix = getpixes[bpp - 1];
  1306.     w = surface->w;
  1307.     h = surface->h;
  1308.  
  1309. #define ADD_COUNTS(n, m)            \
  1310.     if(bpp == 4) {                \
  1311.         ((Uint16 *)dst)[0] = n;        \
  1312.         ((Uint16 *)dst)[1] = m;        \
  1313.         dst += 4;                \
  1314.     } else {                \
  1315.         dst[0] = n;                \
  1316.         dst[1] = m;                \
  1317.         dst += 2;                \
  1318.     }
  1319.  
  1320.     for(y = 0; y < h; y++) {
  1321.         int x = 0;
  1322.         int blankline = 0;
  1323.         do {
  1324.         int run, skip, len;
  1325.         int runstart;
  1326.         int skipstart = x;
  1327.  
  1328.         /* find run of transparent, then opaque pixels */
  1329.         while(x < w && (getpix(srcbuf + x * bpp) & rgbmask) == ckey)
  1330.             x++;
  1331.         runstart = x;
  1332.         while(x < w && (getpix(srcbuf + x * bpp) & rgbmask) != ckey)
  1333.             x++;
  1334.         skip = runstart - skipstart;
  1335.         if(skip == w)
  1336.             blankline = 1;
  1337.         run = x - runstart;
  1338.  
  1339.         /* encode segment */
  1340.         while(skip > maxn) {
  1341.             ADD_COUNTS(maxn, 0);
  1342.             skip -= maxn;
  1343.         }
  1344.         len = MIN(run, maxn);
  1345.         ADD_COUNTS(skip, len);
  1346.         memcpy(dst, srcbuf + runstart * bpp, len * bpp);
  1347.         dst += len * bpp;
  1348.         run -= len;
  1349.         runstart += len;
  1350.         while(run) {
  1351.             len = MIN(run, maxn);
  1352.             ADD_COUNTS(0, len);
  1353.             memcpy(dst, srcbuf + runstart * bpp, len * bpp);
  1354.             dst += len * bpp;
  1355.             runstart += len;
  1356.             run -= len;
  1357.         }
  1358.         if(!blankline)
  1359.             lastline = dst;
  1360.         } while(x < w);
  1361.  
  1362.         srcbuf += surface->pitch;
  1363.     }
  1364.     dst = lastline;        /* back up bast trailing blank lines */
  1365.     ADD_COUNTS(0, 0);
  1366.  
  1367. #undef ADD_COUNTS
  1368.  
  1369.     /* Now that we have it encoded, release the original pixels */
  1370.     if((surface->flags & SDL_PREALLOC) != SDL_PREALLOC
  1371.        && (surface->flags & SDL_HWSURFACE) != SDL_HWSURFACE) {
  1372.         free( surface->pixels );
  1373.         surface->pixels = NULL;
  1374.     }
  1375.  
  1376.     /* realloc the buffer to release unused memory */
  1377.     {
  1378.         /* If realloc returns NULL, the original block is left intact */
  1379.         Uint8 *p = realloc(rlebuf, dst - rlebuf);
  1380.         if(!p)
  1381.         p = rlebuf;
  1382.         surface->map->sw_data->aux_data = p;
  1383.     }
  1384.  
  1385.     return(0);
  1386. }
  1387.  
  1388. int SDL_RLESurface(SDL_Surface *surface)
  1389. {
  1390.     int retcode;
  1391.  
  1392.     /* Clear any previous RLE conversion */
  1393.     if ( (surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) {
  1394.         SDL_UnRLESurface(surface, 1);
  1395.     }
  1396.  
  1397.     /* We don't support RLE encoding of bitmaps */
  1398.     if ( surface->format->BitsPerPixel < 8 ) {
  1399.         return(-1);
  1400.     }
  1401.  
  1402.     /* Lock the surface if it's in hardware */
  1403.     if ( surface->flags & (SDL_HWSURFACE|SDL_ASYNCBLIT) ) {
  1404.         SDL_VideoDevice *video = current_video;
  1405.         SDL_VideoDevice *this  = current_video;
  1406.         if ( video->LockHWSurface(this, surface) < 0 ) {
  1407.             return(-1);
  1408.         }
  1409.     }
  1410.  
  1411.     /* Encode */
  1412.     if((surface->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY) {
  1413.         retcode = RLEColorkeySurface(surface);
  1414.     } else {
  1415.         if((surface->flags & SDL_SRCALPHA) == SDL_SRCALPHA
  1416.            && surface->format->Amask != 0)
  1417.         retcode = RLEAlphaSurface(surface);
  1418.         else
  1419.         retcode = -1;    /* no RLE for per-surface alpha sans ckey */
  1420.     }
  1421.  
  1422.     /* Unlock the surface if it's in hardware */
  1423.     if ( surface->flags & (SDL_HWSURFACE|SDL_ASYNCBLIT) ) {
  1424.         SDL_VideoDevice *video = current_video;
  1425.         SDL_VideoDevice *this  = current_video;
  1426.         video->UnlockHWSurface(this, surface);
  1427.     }
  1428.  
  1429.     if(retcode < 0)
  1430.         return -1;
  1431.  
  1432.     /* The surface is now accelerated */
  1433.     surface->flags |= SDL_RLEACCEL;
  1434.  
  1435.     return(0);
  1436. }
  1437.  
  1438. /*
  1439.  * Un-RLE a surface with pixel alpha
  1440.  * This may not give back exactly the image before RLE-encoding; all
  1441.  * completely transparent pixels will be lost, and colour and alpha depth
  1442.  * may have been reduced (when encoding for 16bpp targets).
  1443.  */
  1444. static void UnRLEAlpha(SDL_Surface *surface)
  1445. {
  1446.     Uint8 *srcbuf;
  1447.     Uint32 *dst;
  1448.     SDL_PixelFormat *sf = surface->format;
  1449.     RLEDestFormat *df = surface->map->sw_data->aux_data;
  1450.     int (*uncopy_opaque)(Uint32 *, void *, int,
  1451.              RLEDestFormat *, SDL_PixelFormat *);
  1452.     int (*uncopy_transl)(Uint32 *, void *, int,
  1453.              RLEDestFormat *, SDL_PixelFormat *);
  1454.     int w = surface->w;
  1455.     int bpp = df->BytesPerPixel;
  1456.  
  1457.     if(bpp == 2) {
  1458.     uncopy_opaque = uncopy_opaque_16;
  1459.     uncopy_transl = uncopy_transl_16;
  1460.     } else {
  1461.     uncopy_opaque = uncopy_transl = uncopy_32;
  1462.     }
  1463.  
  1464.     surface->pixels = malloc(surface->h * surface->pitch);
  1465.     /* fill background with transparent pixels */
  1466.     memset(surface->pixels, 0, surface->h * surface->pitch);
  1467.  
  1468.     dst = surface->pixels;
  1469.     srcbuf = (Uint8 *)(df + 1);
  1470.     for(;;) {
  1471.     /* copy opaque pixels */
  1472.     int ofs = 0;
  1473.     do {
  1474.         unsigned run;
  1475.         if(bpp == 2) {
  1476.         ofs += srcbuf[0];
  1477.         run = srcbuf[1];
  1478.         srcbuf += 2;
  1479.         } else {
  1480.         ofs += ((Uint16 *)srcbuf)[0];
  1481.         run = ((Uint16 *)srcbuf)[1];
  1482.         srcbuf += 4;
  1483.         }
  1484.         if(run) {
  1485.         srcbuf += uncopy_opaque(dst + ofs, srcbuf, run, df, sf);
  1486.         ofs += run;
  1487.         } else if(!ofs)
  1488.         return;
  1489.     } while(ofs < w);
  1490.  
  1491.     /* skip padding if needed */
  1492.     if(bpp == 2)
  1493.         srcbuf += (unsigned long)srcbuf & 2;
  1494.     
  1495.     /* copy translucent pixels */
  1496.     ofs = 0;
  1497.     do {
  1498.         unsigned run;
  1499.         ofs += ((Uint16 *)srcbuf)[0];
  1500.         run = ((Uint16 *)srcbuf)[1];
  1501.         srcbuf += 4;
  1502.         if(run) {
  1503.         srcbuf += uncopy_transl(dst + ofs, srcbuf, run, df, sf);
  1504.         ofs += run;
  1505.         }
  1506.     } while(ofs < w);
  1507.     dst += surface->pitch >> 2;
  1508.     }
  1509. }
  1510.  
  1511. void SDL_UnRLESurface(SDL_Surface *surface, int recode)
  1512. {
  1513.     if ( (surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) {
  1514.     surface->flags &= ~SDL_RLEACCEL;
  1515.  
  1516.     if(recode && (surface->flags & SDL_PREALLOC) != SDL_PREALLOC
  1517.        && (surface->flags & SDL_HWSURFACE) != SDL_HWSURFACE) {
  1518.         if((surface->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY) {
  1519.         SDL_Rect full;
  1520.         unsigned alpha_flag;
  1521.  
  1522.         /* re-create the original surface */
  1523.         surface->pixels = malloc(surface->h * surface->pitch);
  1524.  
  1525.         /* fill it with the background colour */
  1526.         SDL_FillRect(surface, NULL, surface->format->colorkey);
  1527.  
  1528.         /* now render the encoded surface */
  1529.         full.x = full.y = 0;
  1530.         full.w = surface->w;
  1531.         full.h = surface->h;
  1532.         alpha_flag = surface->flags & SDL_SRCALPHA;
  1533.         surface->flags &= ~SDL_SRCALPHA; /* opaque blit */
  1534.         SDL_RLEBlit(surface, &full, surface, &full);
  1535.         surface->flags |= alpha_flag;
  1536.         } else
  1537.         UnRLEAlpha(surface);
  1538.     }
  1539.  
  1540.     if ( surface->map && surface->map->sw_data->aux_data ) {
  1541.         free(surface->map->sw_data->aux_data);
  1542.         surface->map->sw_data->aux_data = NULL;
  1543.     }
  1544.     }
  1545. }
  1546.  
  1547.  
  1548.